package com.lsh.payment.core.service.payment.impl;

import com.alibaba.dubbo.common.utils.StringUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.lsh.payment.api.model.basevo.ExceptionStatus;
import com.lsh.payment.api.model.basevo.QueryContent;
import com.lsh.payment.api.model.payment.PaymentQueryCheckRequest;
import com.lsh.payment.api.model.payment.PaymentQueryRequest;
import com.lsh.payment.core.constant.BusinessConstant;
import com.lsh.payment.core.dao.payment.PayDealDao;
import com.lsh.payment.core.exception.BusinessException;
import com.lsh.payment.core.model.payasync.AliinQueryModel;
import com.lsh.payment.core.model.payasync.CmQueryModel;
import com.lsh.payment.core.model.payasync.MisPurseQueryModel;
import com.lsh.payment.core.model.payasync.QueryModel;
import com.lsh.payment.core.model.payenum.PayChannel;
import com.lsh.payment.core.model.payenum.PayStatus;
import com.lsh.payment.core.model.payenum.PayType;
import com.lsh.payment.core.model.payment.PayDeal;
import com.lsh.payment.core.service.async.PayEventBus;
import com.lsh.payment.core.service.payment.IPayQueryChannelService;
import com.lsh.payment.core.util.Criteria;
import com.lsh.payment.core.util.Pageable;
import com.lsh.payment.core.util.PayAssert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Project Name: lsh-payment
 *
 * @author peter
 * @date 16/11/6
 * 北京链商电子商务有限公司
 * Package
 * desc:
 */
@Service
@Transactional(readOnly = true)
public class PayQueryBaseService {

    private static Logger logger = LoggerFactory.getLogger(PayQueryBaseService.class);

    @Autowired
    private Map<String, IPayQueryChannelService> payQueryChannelServices;

    @Autowired
    private PayDealService payDealService;

    @Resource
    private PayDealDao payDealDao;

    public Pageable<PayDeal> query(Criteria criteria, Long page, Long pageLimit) {
        List<PayDeal> payments = payDealDao.findBaseOnCriteria(criteria, ((page - 1) * pageLimit), pageLimit);
        return new Pageable<>(payments, page);
    }


    @Transactional(rollbackFor = Exception.class)
    public PayDeal queryPayDeal(PaymentQueryRequest paymentQueryRequest) {

        logger.info("查询参数 {}", JSON.toJSONString(paymentQueryRequest));
        PayDeal payDeal = null;
        //支付平台流水号有值
        if (StringUtils.isNotEmpty(paymentQueryRequest.getPay_payment_no())) {
            PayDeal pay = payDealService.queryPayDealByPayPaymentNo(paymentQueryRequest.getPay_payment_no());

            PayAssert.notNull(pay, ExceptionStatus.E2001012.getCode(), ExceptionStatus.E2001012.getMessage() + " payPaymentNo is : " + paymentQueryRequest.getPay_payment_no());

            if (pay.getPayStatus() == PayStatus.PAY_SUCCESS.getValue()) {
                //已经支付成功,直接返回
                payDeal = pay;
            }

        } else {
            List<PayDeal> payList = payDealService.queryPayDealByTradeId(paymentQueryRequest.getTrade_id());
            //交易记录不存在
            PayAssert.notEmpty(payList, ExceptionStatus.E2001012.getCode(), ExceptionStatus.E2001012.getMessage() + " orderId is : " + paymentQueryRequest.getTrade_id());

            for (PayDeal pay : payList) {
                if (pay.getPayStatus() == PayStatus.PAY_SUCCESS.getValue()) {
                    //已经支付成功,直接返回
                    payDeal = pay;
                    break;
                }
            }
        }


        return payDeal;
    }


    public List<Map<String,Object>> queryCheck(PaymentQueryCheckRequest paymentQueryCheckRequest) {
        logger.info("查询参数 {}", JSON.toJSONString(paymentQueryCheckRequest));
        return payDealService.queryCheck(paymentQueryCheckRequest);
    }


    @Transactional(rollbackFor = Exception.class)
    public QueryContent queryPayStatus(PaymentQueryRequest paymentQueryRequest) {

        QueryContent content = new QueryContent();
        logger.info("查询参数 {}", JSON.toJSONString(paymentQueryRequest));
        PayDeal payDeal = null;
        //支付平台流水号有值
        if (StringUtils.isNotEmpty(paymentQueryRequest.getPay_payment_no())) {
            payDeal = payDealService.queryPayDealByPayPaymentNo(paymentQueryRequest.getPay_payment_no());

            PayAssert.notNull(payDeal, ExceptionStatus.E2001012.getCode(), ExceptionStatus.E2001012.getMessage() + " payPaymentNo is : " + paymentQueryRequest.getPay_payment_no());
        } else if (StringUtils.isNotEmpty(paymentQueryRequest.getChannel_transaction())) {
            payDeal = payDealService.queryPayDealByChannelTransaction(paymentQueryRequest.getChannel_transaction());

            PayAssert.notNull(payDeal, ExceptionStatus.E2001012.getCode(), ExceptionStatus.E2001012.getMessage() + " channel_transaction is : " + paymentQueryRequest.getChannel_transaction());

        } else if (StringUtils.isNotEmpty(paymentQueryRequest.getTrade_id())) {
            List<PayDeal> payList = payDealService.queryPayDealByTradeId(paymentQueryRequest.getTrade_id());
            //交易记录不存在
            PayAssert.notEmpty(payList, ExceptionStatus.E2001012.getCode(), ExceptionStatus.E2001012.getMessage() + " orderId is : " + paymentQueryRequest.getTrade_id());

            //1 有一条支付记录,支付成功,返回成功
            for (PayDeal pay : payList) {
                if (pay.getPayStatus() == PayStatus.PAY_SUCCESS.getValue()) {
                    //已经支付成功,直接返回
                    payDeal = pay;
                    break;
                } else if (pay.getPayStatus() == PayStatus.PAYING.getValue() || pay.getPayStatus() == PayStatus.CREATE_PAYMENT.getValue()) {
                    //未支付,后续处理
                    payDeal = pay;
                }
            }

            //多条记录时,没有支付成功,也没有支付中,则支付失败
            if (payDeal == null) {
                content.setPayCode(PayStatus.PAY_FAIL.getValue());
                content.setPayMsg(PayStatus.PAY_FAIL.getName());

                return content;
            }

        } else {

            throw new BusinessException(ExceptionStatus.E1002001.getCode(), "查询支付记录参数异常");
        }

        return this.parsePayDeal(payDeal);
    }


    private void getPayDeal(PayDeal payDeal, QueryContent content) {
        Integer payType = payDeal.getPayType();
        String willCode = "0";
        String pOrderCode = "0";
        List<String> togetherTrades = new ArrayList<>();
        String tradeId = payDeal.getTradeId();
        if (PayType.TOGETHER_PAY.getCode() == payType) {
            JSONObject ext = JSON.parseObject(payDeal.getExt());

            JSONObject dealExt = ext.getJSONObject("ext");
            willCode = dealExt.getString("will_code");
            pOrderCode = dealExt.getString("p_order_code");
            logger.info("dealExt is " + dealExt.toJSONString());
            JSONArray array = dealExt.getJSONArray("together_trades");
            logger.info("dealExt array is " + array);
            togetherTrades = JSONObject.parseArray(array.toJSONString(), String.class);
            if (org.apache.commons.lang3.StringUtils.isBlank(willCode)) {
                String[] willOrder = tradeId.split("_");
                if (willOrder.length == 2) {
                    willCode = willOrder[0];
                    pOrderCode = willOrder[1];
                }
            }
        }

        content.setP_order_code(pOrderCode);
        content.setWill_code(willCode);
        content.setTogetherTrades(togetherTrades);
    }

    /**
     * 解析支付记录状态
     *
     * @param payDeal
     * @return
     */
    private QueryContent parsePayDeal(PayDeal payDeal) {

        QueryContent content = new QueryContent();

        if (payDeal != null) {
            this.setSpeVar(content, payDeal);
        }
        //(1)有一条支付记录,支付成功,返回成功
        if (payDeal != null && payDeal.getPayStatus() != null && payDeal.getPayStatus() == PayStatus.PAY_SUCCESS.getValue()) {
            //已经支付成功,直接返回
            content.setPayCode(PayStatus.PAY_SUCCESS.getValue());
            content.setPayMsg(PayStatus.PAY_SUCCESS.getName());
            logger.info("{} 支付成功", payDeal.getPayPaymentNo());

            this.getPayDeal(payDeal, content);
            return content;
        }

        //(2)没有支付成功和未支付状态的,支付失败
        if (isPayFail(payDeal)) {

            content.setPayCode(PayStatus.PAY_FAIL.getValue());
            content.setPayMsg(PayStatus.PAY_FAIL.getName());
            logger.info("{} 支付失败", payDeal.getPayPaymentNo());
            return content;
        }

        logger.info("{} 调用第三方查询接口,同步支付结果", payDeal.getPayPaymentNo());
        //(3)未支付,调第三方进行查询
        //微信
        if (payDeal.getPayChannel().equals(PayChannel.WXPAY.getName())) {
            content = payQueryChannelServices.get(BusinessConstant.QUERY_WX_SERVICE_NAME).query(payDeal);
        } else if (payDeal.getPayChannel().equals(PayChannel.ALIPAY.getName())) {
            content = payQueryChannelServices.get(BusinessConstant.QUERY_ALI_SERVICE_NAME).query(payDeal);
        } else if (payDeal.getPayChannel().equals(PayChannel.QFPAY.getName())) {

            PayEventBus.post(new QueryModel(payDeal));
            content.setPayCode(PayStatus.PAYING.getValue());
            content.setPayMsg(PayStatus.PAYING.getName());
        } else if (payDeal.getPayChannel().equals(PayChannel.ALLINPAY.getName())) {
            PayEventBus.post(new AliinQueryModel(payDeal));
            content.setPayCode(PayStatus.PAYING.getValue());
            content.setPayMsg(PayStatus.PAYING.getName());
//            content = payQueryChannelServices.get(BusinessConstant.QUERY_ALLIN_SERVICE_NAME).query(payDeal);
        } else if (payDeal.getPayChannel().equals(PayChannel.CMPAY.getName())) {
            PayEventBus.post(new CmQueryModel(payDeal));
            content.setPayCode(PayStatus.PAYING.getValue());
            content.setPayMsg(PayStatus.PAYING.getName());
//            content = payQueryChannelServices.get(BusinessConstant.QUERY_CM_SERVICE_NAME).query(payDeal);
        } else if (payDeal.getPayChannel().equals(PayChannel.PURSE_PRE_PAY.getName()) ||
                payDeal.getPayChannel().equals(PayChannel.PURSE_ON_CREDIT_PAY.getName()) ||
                payDeal.getPayChannel().equals(PayChannel.PURSE_BALANCE_PAY.getName())) {

            PayEventBus.post(new MisPurseQueryModel(payDeal));
            content.setPayCode(PayStatus.PAYING.getValue());
            content.setPayMsg(PayStatus.PAYING.getName());
//            content = payQueryChannelServices.get(BusinessConstant.QUERY_MIS_SERVICE_NAME).query(payDeal);
        }

        this.getPayDeal(payDeal, content);

        return content;
    }

    private void setSpeVar(QueryContent content, PayDeal payDeal) {

        content.setTradeId(payDeal.getTradeId());
        content.setChannelTransaction(payDeal.getChannelTransaction());
    }

    /**
     * 判断是否支付失败,没有支付成功,也没有支付中,
     *
     * @param payDeal
     */
    private boolean isPayFail(PayDeal payDeal) {
        if (payDeal == null) {
            return false;
        }
        //支付成功
        if (payDeal.getPayStatus() == PayStatus.PAY_SUCCESS.getValue()) {
            return false;
        }
        //支付中
        if (payDeal.getPayStatus() == PayStatus.PAYING.getValue() || payDeal.getPayStatus() == PayStatus.CREATE_PAYMENT.getValue()) {
            return false;
        }
        //单方面关单
        if (payDeal.getPayStatus() == PayStatus.PAY_CLOSE.getValue()) {
            return false;
        }
        //支付失败
        return true;
    }


}
